# AUTHOR:   Zachary Mott
# DATE:     2012-11-25

# thanks to www.easyrgb.com/index.php?X=MATH for RGBtoXYZ
# and RGBtoHueSat

# thanks to rsmck.co.uk/hue for background regarding Hue
# interface.

# thanks to burgestrand.github.com/hue-api/ for API!

import requests
import json
import time
import math

 
import HueConf

def RGBtoHueSat(r, g, b):

    r /= 255.0
    g /= 255.0
    b /= 255.0

    min_ = min(r, g, b)
    max_ = max(r, g, b)

    dMax = max_ - min_
    L = (max_ + min_) / 2.0

    if dMax == 0:
        hue = 0
        sat = 0
    else:
        if L < .5:
            sat = dMax / (max_ + min_)
        else:
            sat = dMax / (2 - max_ - min_)

        dR = ( ((max_ - r) / 6.0) + (dMax / 2.0) ) / dMax
        dG = ( ((max_ - g) / 6.0) + (dMax / 2.0) ) / dMax
        dB = ( ((max_ - b) / 6.0) + (dMax / 2.0) ) / dMax

        if r == max_:
            hue = dB - dG
        elif g == max_:
            hue = (1/3.0) + dR - dB
        elif b == max_:
            hue = (2/3.0) + dG - dR

    if hue < 0:
        hue += 1
    if hue > 1:
        hue -= 1

    return hue, sat


def RGBtoXYZ(r, g, b):

    adjusted_colors = [r, g, b]

    for idx, c in enumerate(adjusted_colors):
        c += 1
        c /= 255.0
        if c > .04045:
            c = ( (c + .055) / 1.055 ) ** 2.4
        else:
            c /= 12.92

        adjusted_colors[idx] = c

    r = adjusted_colors[0]
    g = adjusted_colors[1]
    b = adjusted_colors[2]

    x = (r * .4124) + (g * .3576) + (b * .1805)
    y = (r * .2126) + (g * .7152) + (b * .0722)
    z = (r * .0193) + (g * .1192) + (b * .9505)

    return x, y, z

def query(lamps, data=None):
    results = {}

    if not isinstance(lamps, list):
        lamps = [lamps]

    lamps = [str(lamp) for lamp in lamps]

    sleep_time = 0

    for l in lamps:
        if data:
            r = requests.put( HueConf.PUT_URL % l,
                        data=json.dumps(data),
                        timeout=HueConf.TIMEOUT
                )
        else:
            r = requests.get(HueConf.GET_URL % l,
                        timeout=HueConf.TIMEOUT
                )

        results[l] = r
        time.sleep(sleep_time)


    return results

def status(lamps):
    return query(lamps)

def put(lamps, data):
    return query(lamps, data)

def off(lamps):
    return query(lamps, {'on': False, 'transitiontime': 0})

def on(lamps):
    return query(lamps, {'on': True})

def color(lamps, r=0, g=0, b=0, data={}):
#   CIE 1931 color mode wasn't working as well as I wanted it to, so
#   I switched to Hue/Saturation.
#    x, y, z = RGBtoXYZ(r, g, b)
#    data.update( {'xy': [x, y]} )

    h, s = RGBtoHueSat(r, g, b)

#   RGBtoHueSat gives values in a range from 0-1, so we gotta
#   convert the results to a scale that makes sense.
    h = int(h *360*182.04)
    s = int(s*254)

    data.update( {'hue': h, 'sat': s} )

    return put(lamps, data)
